#include "netServer.hpp"
#include <chrono>
#include <cstdint>
#include <iostream>
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <thread>
#include <unistd.h>
#include "clientThread.hpp"

using namespace std;

NetServer::~NetServer()
{
    if (serverSkt > 0)
    {
        Close();
    }
}

bool NetServer::Open(std::string ip, uint16_t port, int maxAccept)
{
    serverSkt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    sockaddr_in address;
    inet_pton(AF_INET, ip.c_str(), &address.sin_addr.s_addr);
    address.sin_port = htons(port);
    address.sin_family = AF_INET;

    int ret = bind(serverSkt, (sockaddr *)&address, sizeof(sockaddr_in));
    if (ret == -1)
    {
        cout << "Bind socket fail" << endl;
        return false;
    }
    closeServerFlag = false;
    listen(serverSkt, maxAccept);
    listenThread = thread(&NetServer::Listen, this);
    return true;
}

void NetServer::Listen()
{
    while (!closeServerFlag)
    {
        struct sockaddr_in clientAddr = {0};
        unsigned int clientAddrSize = sizeof(sockaddr_in);
        int clientSkt = accept(serverSkt, (sockaddr *)&clientAddr, &clientAddrSize);
        if (clientSkt >= 0)
        {
            char clientIP[16];
            inet_ntop(AF_INET, &clientAddr.sin_addr.s_addr, clientIP, sizeof(clientIP));
            unsigned short clientPort = ntohs(clientAddr.sin_port);
            cout << string("Client connect at ") + clientIP + ':' + to_string(clientPort) + '\n';
            ClientThread *newClient = new ClientThread(this, clientSkt);
            newClient->Run();
            clientThreads.push_back(newClient);
            // clientThreads.push_back(thread(&NetServer::ClientLoop, this, clientSkt));
        }
        this_thread::sleep_for(chrono::milliseconds(100));
    }
    close(serverSkt);
    return;
}

void NetServer::Close()
{
    closeServerFlag = true;
    // listenThread.join();//accept is block maybe this will stop funcion
    for (int i = 0; i < clientThreads.size(); i++)
    {
        clientThreads[i]->Close();
        delete clientThreads[i];
    }
    clientThreads.clear();
}

void NetServer::SetValue(std::string key, float value)
{
    SetValue(key, to_string(value));
}

void NetServer::SetValue(std::string key, int value)
{
    SetValue(key, to_string(value));
}

void NetServer::SetValue(std::string key, std::string value)
{
    valueDic[key] = value;
}

bool NetServer::GetValue(std::string key, float &value)
{
    auto iterator = valueDic.find(key);
    if (iterator == valueDic.end())
    {
        return false;
    }
    value = stof(iterator->second);
    return true;
}

bool NetServer::GetValue(std::string key, int &value)
{
    auto iterator = valueDic.find(key);
    if (iterator == valueDic.end())
    {
        return false;
    }
    value = stoi(iterator->second);
    return true;
}

bool NetServer::GetValue(std::string key, std::string &value)
{
    auto iterator = valueDic.find(key);
    if (iterator == valueDic.end())
    {
        return false;
    }
    value = iterator->second;
    return true;
}

float NetServer::GetValueOrDefault(std::string key, float def)
{
    float val;
    if (GetValue(key, val))
        return val;
    else
        return def;
}

int NetServer::GetValueOrDefault(std::string key, int def)
{
    int val;
    if (GetValue(key, val))
        return val;
    else
        return def;
}

std::string NetServer::GetValueOrDefault(std::string key, std::string def)
{
    string val;
    if (GetValue(key, val))
        return val;
    else
        return def;
}

void NetServer::ChangeFrequent(int intervalMs)
{
    this->updateInterval = intervalMs;
}

void NetServer::ClientLoop(int clientSkt)
{
    char recvBuf[1024] = {0};
    while (!closeServerFlag)
    {
        // 获取客户端的数据
        int num = read(clientSkt, recvBuf, sizeof(recvBuf));
        if (num == -1)
        {
            perror("read from client fail");
            exit(-1);
        }
        else if (num > 0)
        {
            printf("recv client data : %s\n", recvBuf);
        }
        else if (num == 0)
        {
            // 表示客户端断开连接
            printf("clinet closed...");
            break;
        }

        string data = "hello,i am server";
        // 给客户端发送数据
        write(clientSkt, data.data(), data.size());
    }
    close(clientSkt);
}